package com.ai.gesture.service.impl;

/**
 * ClassName:    GestureRecognitionServiceImpl
 * Description:  TODO
 * Author:       yuzx
 * Date:         2025/9/9 09:34
 * Version:      1.0
 **/


import com.ai.common.core.domain.AjaxResult;
import com.ai.gesture.domain.dto.GestureRecognitionRequest;
import com.ai.gesture.domain.dto.GestureRecognitionResponse;
import com.ai.gesture.service.IGestureRecognitionService;
import com.ai.bd_util.BaiduAipUtil;
import com.ai.bd_util.BaiduAuthUtil;
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 手势识别服务实现类（完全对齐百度官方API规范，已修复所有编译错误）
 */
@Service
public class GestureRecognitionServiceImpl implements IGestureRecognitionService {
    // 日志组件（打印关键流程和错误）
    private static final Logger log = LoggerFactory.getLogger(GestureRecognitionServiceImpl.class);

    // 百度手势识别API配置（从application.yml读取）
    @Value("${baidu.ai.gesture.api-url}")
    private String gestureApiUrl; // 官方API地址：https://aip.baidubce.com/rest/2.0/image-classify/v1/gesture
    @Value("${baidu.ai.gesture.max-size}")
    private long maxImageSize; // 图片最大4M（字节）

    // 注入鉴权工具类（已确保能成功获取access_token）
    @Resource
    private BaiduAuthUtil baiduAuthUtil;

    // OkHttp客户端（全局单例，避免重复创建）
    private OkHttpClient httpClient;

    /**
     * 初始化OkHttp客户端（Bean创建后自动执行，避免多次初始化）
     */
    @PostConstruct
    public void initOkHttpClient() {
        this.httpClient = new OkHttpClient().newBuilder().build();
        log.info("OkHttp客户端初始化完成，用于调用百度手势识别API");
    }

    /**
     * 核心方法：调用百度API完成手势识别
     *
     * @param request 前端传递的请求DTO（含图片Base64编码）
     * @return 识别结果（成功返回数据，失败返回错误信息）
     */
    @Override
    public AjaxResult recognizeGesture(GestureRecognitionRequest request) {
        try {
            // 1. 提取并校验前端传递的Base64图片（确保参数合法）
            String base64Image = request.getBase64Image();
            validateBase64Image(base64Image);
            log.info("接收前端图片Base64编码，字符长度：{}（预估图片大小：{:.2f}KB）",
                    base64Image.length(), (base64Image.length() * 3 / 4) / 1024.0);

            // 2. 图片参数编码（对齐百度官方流程：Base64 → URL编码）
            String encodedImage = BaiduAipUtil.encodeImageParam(base64Image);
            String requestParam = "image=" + encodedImage; // 官方要求的参数格式：key=value
            log.info("构造手势识别请求参数（前100字符脱敏展示）：{}...",
                    requestParam.substring(0, Math.min(100, requestParam.length())));

            // 3. 获取有效access_token（鉴权工具类已处理缓存和过期刷新）
            String accessToken = baiduAuthUtil.getValidAccessToken();
            log.info("获取到有效access_token（前20字符脱敏展示）：{}...",
                    accessToken.substring(0, Math.min(20, accessToken.length())));

            // 4. 构造百度手势识别请求URL（官方规范：access_token拼在URL后）
            String requestUrl = gestureApiUrl + "?access_token=" + accessToken;
            log.info("百度手势识别请求URL（脱敏展示）：{}...",
                    requestUrl.substring(0, Math.min(150, requestUrl.length())));

            // 5. 构造请求体（官方要求：application/x-www-form-urlencoded格式）
            MediaType formMediaType = MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8");
            RequestBody requestBody = RequestBody.create(
                    formMediaType,
                    requestParam.getBytes(StandardCharsets.UTF_8) // 确保字符集与官方一致
            );

            // 6. 构造OkHttp请求（变量名用baiduRequest，避免与方法参数request重名）
            Request baiduRequest = new Request.Builder()
                    .url(requestUrl)
                    .method("POST", requestBody)
                    .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") // 官方强制要求的请求头
                    .addHeader("Accept", "application/json") // 期望返回JSON格式响应
                    .build();

            // 7. 发送请求并获取响应（同步调用，确保结果实时返回）
            Response response = httpClient.newCall(baiduRequest).execute();
            String responseBody = response.body().string(); // 读取完整响应内容
            log.info("百度手势识别API完整响应：{}", responseBody); // 关键日志：排查问题的核心依据

            // 8. 校验HTTP响应状态（非200 OK直接抛异常）
            if (!response.isSuccessful()) {
                throw new IOException(String.format(
                        "百度API请求失败，HTTP状态码：%d，响应内容：%s",
                        response.code(), responseBody
                ));
            }

            // 9. 解析百度响应，转换为自定义VO（给前端返回友好格式）
            GestureRecognitionResponse recognitionResult = parseOfficialResponse(responseBody);

            // 10. 返回成功结果（携带识别数据）
            return AjaxResult.success("手势识别成功", recognitionResult);

        } catch (IllegalArgumentException e) {
            // 处理参数校验失败（如图片为空、大小超限）
            log.warn("手势识别参数校验失败：{}", e.getMessage());
            return AjaxResult.error("参数错误：" + e.getMessage());
        } catch (JSONException e) {
            // 处理JSON解析失败（如百度返回非预期格式）
            log.error("百度响应JSON解析失败", e);
            return AjaxResult.error("识别结果解析失败：" + e.getMessage());
        } catch (Exception e) {
            // 处理其他未知异常（如网络错误、鉴权失败）
            log.error("手势识别流程异常", e);
            return AjaxResult.error("识别失败：" + e.getMessage());
        }
    }

    /**
     * 辅助方法：校验Base64图片的合法性（非空、大小超限）
     *
     * @param base64Image 前端传递的图片Base64编码（不含图片头）
     */
    private void validateBase64Image(String base64Image) {
        // 校验非空（用hasText兼容低版本Spring，等效于!isBlank）
        if (!StringUtils.hasText(base64Image)) {
            throw new IllegalArgumentException("图片Base64编码不能为空，请重新上传图片");
        }

        // 计算Base64对应的真实图片字节大小（公式：Base64长度*3/4 - 填充符数量）
        long imageSize = (base64Image.length() * 3L) / 4 - countBase64Padding(base64Image);
        // 校验大小（不超过配置的maxImageSize，默认4M）
        if (imageSize > maxImageSize) {
            throw new IllegalArgumentException(String.format(
                    "图片大小超限（最大支持%dMB），当前图片大小：%.2fMB",
                    maxImageSize / 1024 / 1024, imageSize / 1024.0 / 1024.0
            ));
        }
    }

    /**
     * 辅助方法：统计Base64编码的填充符（=）数量（用于计算真实图片大小）
     *
     * @param base64Image Base64字符串
     * @return 填充符数量（0-2个）
     */
    private int countBase64Padding(String base64Image) {
        int paddingCount = 0;
        // 从字符串末尾向前统计=的数量
        for (int i = base64Image.length() - 1; i >= 0; i--) {
            if (base64Image.charAt(i) == '=') {
                paddingCount++;
            } else {
                break; // 遇到非=字符，停止统计
            }
        }
        return paddingCount;
    }

    /**
     * 辅助方法：解析百度官方响应，转换为自定义VO
     *
     * @param responseBody 百度API返回的原始JSON字符串
     * @return 自定义的识别结果VO
     * @throws JSONException JSON解析异常（响应格式非预期）
     */
    private GestureRecognitionResponse parseOfficialResponse(String responseBody) throws JSONException {
        // 解析原始JSON响应
        JSONObject responseJson = new JSONObject(responseBody);

        // 优先判断百度返回的错误（若有error字段，直接抛异常）
        if (responseJson.has("error")) {
            String errorMsg = responseJson.optString("error_description", "未知错误");
            throw new JSONException("百度API返回错误：" + errorMsg);
        }

        // 初始化自定义响应VO
        GestureRecognitionResponse resultVO = new GestureRecognitionResponse();
        // 解析基础字段（log_id用于百度问题定位，result_num是识别结果数量）
        resultVO.setLogId(responseJson.getLong("log_id"));
        resultVO.setResultNum(responseJson.getInt("result_num"));

        // 解析核心识别结果（result数组）
        JSONArray resultArray = responseJson.getJSONArray("result");
        if (resultArray == null || resultArray.length() == 0) {
            throw new JSONException("百度API未返回有效识别结果（result数组为空）");
        }

        // 转换result数组为自定义List<RecognitionResult>
        List<GestureRecognitionResponse.RecognitionResult> resultList = new ArrayList<>();
        for (int i = 0; i < resultArray.length(); i++) {
            JSONObject itemJson = resultArray.getJSONObject(i);
            GestureRecognitionResponse.RecognitionResult itemVO = new GestureRecognitionResponse.RecognitionResult();

            // 映射百度返回的字段（与官方文档完全对应）
            itemVO.setClassname(itemJson.getString("classname")); // 手势类别（如Fist、OK、Heart）
            itemVO.setProbability((float) itemJson.getDouble("probability")); // 识别概率（0-1）
            itemVO.setTop(itemJson.getInt("top")); // 目标框上坐标（像素）
            itemVO.setLeft(itemJson.getInt("left")); // 目标框左坐标（像素）
            itemVO.setWidth(itemJson.getInt("width")); // 目标框宽度（像素）
            itemVO.setHeight(itemJson.getInt("height")); // 目标框高度（像素）

            resultList.add(itemVO);
        }
        resultVO.setResultList(resultList);

        return resultVO;
    }
}